package org.geof.data;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

import org.geof.log.GLogger;

/**
 * Provides Video specific information for a file uploaded to server
 * 
 * @author Jeff Boehmer
 * @comanpay  Ft Collins Research, LLC.
 * @url	www.ftcollinsresearch.org
 *
 */
public class VideoInfo {
	// 1 video H264 High@3, 305.071 secs, 821 kbps, 640x368 @ 29.970073 fps
	public String Format = "";
	public double Length = 0.0;
	public int Rate = 0;
	public int Width = 0;
	public int Height = 0;
	public double FPS = 0.0;

	// 2 audio MPEG-4 AAC LC, 305.152 secs, 48 kbps, 24000 Hz
	public String AudFormat = "";
	public double AudLength = 0.0;
	public int AudRate = 0;
	public int AudFreq = 0;

	/**
	 * Class Constructor
	 */
	public VideoInfo() {
	}

	/**
	 * Class Constructor with video information in an array of strings.
	 * 
	 * @param data Video data generated by mp4split program
	 */
	public VideoInfo(ArrayList<String> data) {
		parse(data);
	}

	/**
	 * Class Constructor with video information in a text file
	 * 
	 * @param file file containing video data generated by mp4split program
	 *
	 */
	public VideoInfo(File file) {
		ArrayList<String> data = readfile(file);
		parse(data);
	}

	/**
	 * Reads video data from file and converts that into an array of strings
	 * 
	 * @param file  File containing video data
	 * @return 
	 */
	private ArrayList<String> readfile(File file) {
		try {
			ArrayList<String> data = new ArrayList<String>();
			FileInputStream fis = new FileInputStream(file);
			BufferedReader br = new BufferedReader(new InputStreamReader(fis));
			String line; // Temporary String variable
			while ((line = br.readLine()) != null) {
				data.add(line);
			}
			br.close(); // Done.

			return data;
		} catch (Exception e) {
			GLogger.error(e);
			return null;
		}
	}

	/**
	 * Extracts video information from array of strings.
	 * 
	 * @param data  Array of strings containing video spec information
	 * @return True if parsing is successful, false if error occurs
	 */
	public boolean parse(ArrayList<String> data) {
		try {
			ArrayList<String> lineTokens;
			String tkn;

			for (String line : data) {
				lineTokens = parseLine(line, 2);
				if (lineTokens.size() > 3) {
					if (lineTokens.get(1).equalsIgnoreCase("video")) {
						// H264 High@3, 305.071 secs, 821 kbps, 640x368 @ 29.970073 fps
						tkn = lineTokens.get(2).trim();
						Format = tkn.substring(0, tkn.indexOf(' ')).trim();

						tkn = lineTokens.get(3).trim();
						Length = Double.parseDouble(tkn.substring(0, tkn.indexOf(' ')).trim());

						tkn = lineTokens.get(4).trim();
						Rate = Integer.parseInt(tkn.substring(0, tkn.indexOf(' ')).trim());

						tkn = lineTokens.get(5).trim();
						int indx = tkn.indexOf('x');
						Width = Integer.parseInt(tkn.substring(0, indx).trim());
						indx++;
						int indx2 = tkn.indexOf('@', indx);
						Height = Integer.parseInt(tkn.substring(indx, indx2).trim());
						indx2 += 2;
						indx = tkn.indexOf(' ', indx2);
						FPS = Double.parseDouble(tkn.substring(indx2, indx).trim());

					} else if (lineTokens.get(1).equalsIgnoreCase("audio")) {
						// MPEG-4 AAC LC, 305.152 secs, 48 kbps, 24000 Hz
						tkn = lineTokens.get(2).trim();
						AudFormat = tkn.substring(0, tkn.indexOf(' ')).trim();

						tkn = lineTokens.get(3).trim();
						AudLength = Double.parseDouble(tkn.substring(0, tkn.indexOf(' ')).trim());

						tkn = lineTokens.get(4).trim();
						AudRate = Integer.parseInt(tkn.substring(0, tkn.indexOf(' ')).trim());

						tkn = lineTokens.get(5).trim();
						int indx = tkn.indexOf(' ');
						AudFreq = Integer.parseInt(tkn.substring(0, indx).trim());
					}
				}
			}
			//GLogger.error(toString());
			return true;

		} catch (Exception e) {
			// System.out.println(e);
			GLogger.error(e);
			return false;
		}
	}

	/**
	 * Converts a String of characters in to an array of name/value pairs
	 * 
	 * @param line  Input string containing video data to be split into array of name/pairs
	 * @param wsCount  WhiteSpace token size
	 * @return  Array of strings contains video data as name pairs
	 */
	private ArrayList<String> parseLine(String line, int wsCount) {
		try {
			ArrayList<String> data = new ArrayList<String>();
			StringBuilder sb = new StringBuilder();
			line = line.trim();
			StringTokenizer st = new StringTokenizer(line);
			int valueCount = 0;
			String token;
			while (st.hasMoreTokens()) {
				token = st.nextToken();
				if (valueCount < wsCount) {
					data.add(token);
					valueCount++;
				} else {
					int tlength = token.length() - 1;
					sb.append(" ").append(token);
					if (token.charAt(tlength) == ',') {
						data.add(sb.substring(1, sb.length() - 2));
						sb.setLength(0);
					}
				}
			}
			if (sb.length() > 0) {
				data.add(sb.substring(1));
			}
			return data;
		} catch (Exception e) {
			// System.out.println(e);
			GLogger.error(e);
			return null;
		}
	}

	/**
	 * Converts Object information into comma delimited list of name/value pair based string
	 * @returns Comma delimited list of Name/Value pair based String.
	 */
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("Format: ").append(Format).append("Length: ").append(Length).append(", Rate: ").append(Rate).append(", Width: ").append(Width).append(
				", Height: ").append(Height).append(", FPS: ").append(FPS).append(", AudFormat: ").append(AudFormat).append(", AudLength: ").append(AudLength)
				.append(", AudRate: ").append(AudRate).append(", AudFreq: ").append(AudFreq);
		return sb.toString();
	}
}
